package com.qf.ability.gateway.security.filter;

import com.qf.common.core.utils.JsonUtils;
import com.qf.data.entity.auth.base.BaseUser;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Optional;

/**
 * Gateway全局过滤器 - 获取当前认证通过的用户信息，继续往后传递
 */
@Component
public class AuthenticationUserInfoFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获得当前登录成功的用户信息
        return ReactiveSecurityContextHolder.getContext()
                //因为某些请求无需通过认证，所有可能拦截器中的SecurityContext对象为null,
                //如果该对象为null，则后续的flatMap方法就不会触发，也就无法放行请求
                //这行代码就是将securityContext对象转换成Optional对象，Optinal对象一定不为null，在后续的flatMap中再去做SecurityContext对象的非null判断
                .flatMap(securityContext -> Mono.just(Optional.ofNullable(securityContext)))
                .defaultIfEmpty(Optional.empty())
                .flatMap(optional -> {

                    if (!optional.isPresent()) {
                        //直接放行
                        return chain.filter(exchange);
                    }

                    //security上下文对象不为null
                    Authentication authentication = optional.get().getAuthentication();
                    BaseUser baseUser = (BaseUser) authentication.getPrincipal();
                    //当前的用户信息对象
                    //设置权限信息
                    List<GrantedAuthority> authorities = (List<GrantedAuthority>)authentication.getAuthorities();
                    baseUser.setAuthorities(authorities);

                    //将用户信息往后传递 （SysUserVo -> json -> request(Header)）
                    String json = JsonUtils.obj2json(baseUser);
                    //将json内容通过url编码
                    try {
                        json = URLEncoder.encode(json, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }

                    //获取当前请求
                    ServerHttpRequest request = exchange.getRequest();

                    //获取请求头 - 当前请求头是只读的，不能直接修改
                    HttpHeaders oldHeaders = request.getHeaders();
                    //创建一个新的请求头，将老的请求头的数据拷贝过去
                    HttpHeaders newHeaders = HttpHeaders.writableHttpHeaders(oldHeaders);
                    newHeaders.set("user_info", json);

                    //再创建一个新的请求
                    ServerHttpRequest newRequest = new ServerHttpRequestDecorator(request) {
                        //重写获取请求头
                        @Override
                        public HttpHeaders getHeaders() {
                            return newHeaders;
                        }
                    };

                    //放行
                    return chain.filter(exchange.mutate().request(newRequest).build());
                });
    }
}
